package net.yihang.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RestController
public class HashCodeController {

    private static int totalCount = 479828;

    @GetMapping("/hashCode")
    public Map<String, Object> hashcode(@RequestParam(defaultValue = "31") int n) {
        int y = 32 - 6; // 2^6 = 64(划分的区域个数),  32是int整数长度
        // 统计分布的map集合
        TreeMap<Integer, Integer> data = new TreeMap<>();
        // 统计冲突率的map集合
        Map<Integer, List<String>> collide = new HashMap<>();
        try (BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream("d:/words")))) {
            r.lines().forEach(line -> {
                int hash = hash(line, n);
                data.compute((hash >> y), (k, v) -> v == null ? 1 : v + 1);
                collide.computeIfAbsent(hash, k -> new ArrayList<>()).add(line);
            });
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 总单词数
        //int count = data.values().stream().reduce((a, b) -> a + b).get();
        int size = totalCount-collide.values().size();
        System.out.println(size);
        BigDecimal ratio = new BigDecimal("" + size).divide(new BigDecimal("" + totalCount), 8, BigDecimal.ROUND_HALF_UP);

        Map<String, Object> result = new HashMap<>();
        result.put("data", data);
        result.put("ratio", ratio);
        result.put("collide", size);
        return result;
    }

    /**
     * 根据不同的质数计算字符串的hash值
     *
     * @param s 字符串
     * @param n 质数
     * @return
     */
    private int hash(String s, int n) {
        int h = 0;
        if (s.length() > 0) {
            char val[] = s.toCharArray();

            for (int i = 0; i < val.length; i++) {
                h = n * h + val[i];
            }
        }
        return h;
    }

    @GetMapping("/hashCodes")
    public Map<String, Object> hashcodes(@RequestParam(defaultValue = "31") int[] ns) {
        System.out.println(Arrays.toString(ns));

        // key 质数       hash区间编号  这个区间的单词个数
        Map<Integer, Map<Integer, Integer>> datas = new HashMap<>();
        // key 质数       hash值   冲突单词集合
        Map<Integer, Map<Integer, List<String>>> collides = new LinkedHashMap<>();

        try (BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream("d:/words")))) {
            int y = 32 - 6; // 2^6 = 64(划分的区域个数),  32是int整数长度
            r.lines().forEach(line -> {
                for (int n : ns) {
                    int hash = hash(line, n);
                    datas.computeIfAbsent(n, k -> new TreeMap<>()).compute(hash >> y, (k, v) -> v == null ? 1 : v + 1);
                    collides.computeIfAbsent(n, k -> new HashMap<>()).computeIfAbsent(hash, k -> new ArrayList<>()).add(line);
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }

        Set<Integer> numbers = datas.keySet();
        List<Series> series = new ArrayList<>();
        List<String> legendData = new ArrayList<>();
        int[] xAxisData = null;
        for (Integer number : numbers) {
            Map<Integer, Integer> map = datas.get(number);
            int[] data = map.values().stream().mapToInt(i -> i).toArray();
            legendData.add("" + number);
            series.add(new Series("" + number, data));
            xAxisData = map.keySet().stream().mapToInt(i -> i).toArray();
        }

        List<Integer> collideNumbers = collides.values().stream().map(m -> totalCount-m.values().size()).collect(Collectors.toList());
        System.out.println(collideNumbers);

        Map<String, Object> result = new HashMap<>();
        result.put("legendData", legendData);
        result.put("series", series);
        result.put("xAxisData", xAxisData);
        result.put("collideNumbers", collideNumbers);
        return result;
    }


}

class Series {
    private String name;
    private String type = "line";
    private int[] data;
    private Map<String, Object> areaStyle = new HashMap<>();

    public Map<String, Object> getAreaStyle() {
        return areaStyle;
    }

    public void setAreaStyle(Map<String, Object> areaStyle) {
        this.areaStyle = areaStyle;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public int[] getData() {
        return data;
    }

    public void setData(int[] data) {
        this.data = data;
    }

    public Series(String name, int[] data) {
        this.name = name;
        this.data = data;
    }
}
